package com.ncu.spring.aop.proxy;

import com.ncu.spring.aop.advisor.*;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 实际上就是个 ProxyConfig，每个代理对象都持有一个 ProxyFactory
 * 一个 ProxyFactory 只能生产一个代理对象
 */
public class ProxyFactory {
    //低级切面集合
    private List<Advisor> advisorList;
    //当前代理类的目标对象 存放在其中
    private TargetSource targetSource;
    //目标类 实现的接口
    private List<Class<?>> interfaces;
    //true，表示使用CGLIB的方式产生代理对象，false，表示使用JDK动态代理
    private boolean proxyTargetClass;
    //到时候作为载体 当要获取
    private static final Class<?>[] EMPTY_CLASS_ARRAY = {};
    //是否允许代理对象作为 ThreadLocal 通过 AopContext 访问
    private boolean exposeProxy = true;

    public ProxyFactory() {
        this.proxyTargetClass = false; //默认使用JDK动态代理
        this.advisorList = new ArrayList<>();
        this.interfaces = new ArrayList<>();
    }
    //将所有低级切面加入ProxyConfig中
    public void addAdvisors(List<Advisor> advisorList) {
        this.advisorList.addAll(advisorList);
    }
    //获取代理
    public Object getProxy() {
        AopProxy aopProxy = createAopProxy(); //创建代理类
        return aopProxy.getProxy(); //获取代理对象
    }

    public AopProxy createAopProxy() {
        if (isProxyTargetClass()) {
            //如果是CGLIB动态代理 就创建一个CGLIB的动态代理对象
            return new ObjenesisCglibAopProxy(this);
        } else {
            //如果 ProxyFactory中 有接口 就创建一个JDK动态代理
            if (!this.interfaces.isEmpty()) {
                return new JdkDynamicAopProxy(this);
            } else {
                // 没接口 就还是创建CGLIB动态代理
                return new ObjenesisCglibAopProxy(this);
            }
        }
    }

    /**
     * TODO：没有实现动态通知调用
     * 得到此 method 的拦截器链，就是一堆环绕通知
     * 需要根据 invoke 的 method 来做进一步确定，过滤出应用在这个 method 上的 Advice
     */
    //将这个对象的 Advisors 转换成 MethodInterceptors 并返回
    //通过methodMatcher 的matches 进行判断
    public List<Interceptor> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
        List<Interceptor> interceptorList = new ArrayList<>(this.advisorList.size());
        for (Advisor advisor : this.advisorList) {
            MethodMatcher methodMatcher = advisor.getPointcut().getMethodMatcher();
            // 切点表达式匹配才添加此 MethodInterceptor
            if (methodMatcher.matches(method, targetClass)) {
                Advice advice = advisor.getAdvice();
                if (advice instanceof MethodInterceptor) {
                    interceptorList.add((MethodInterceptor) advice);
                }
            }
        }
        return interceptorList;
    }
    //设置目标对象 将目标对象 转换成SingletonTargetSource 进行存放
    public void setTarget(Object bean) {
        setTargetSource(new SingletonTargetSource(bean));
    }
    //设置目标对象
    public void setTargetSource(TargetSource targetSource) {
        this.targetSource = targetSource;
    }
    //获取目标对象
    public TargetSource getTargetSource() {
        return targetSource;
    }

    //返回 代理的判断：JDK or CGLIB
    public boolean isProxyTargetClass() {
        return proxyTargetClass;
    }
    //设置 目标类实现的接口
    public void addInterface(Class<?> intf) {
        if (!intf.isInterface()) { //如果不是接口 抛出异常
            throw new IllegalArgumentException(intf.getName() + " ： 不是一个接口");
        }
        // 避免重复添加相同的接口
        if (!this.interfaces.contains(intf)) {
            this.interfaces.add(intf);
        }
    }
    //设置多个 目标类实现的 接口
    public void setInterfaces(Class<?>... interfaces) {
        this.interfaces.clear();
        for (Class<?> intf : interfaces) {
            addInterface(intf);
        }
    }
    //将 目标类实现的接口集合转换成 数组并返回
    public Class<?>[] getProxiedInterfaces() {
        return this.interfaces.toArray(EMPTY_CLASS_ARRAY);
    }
    //获取 是否允许代理对象作为 ThreadLocal 通过 AopContext 访问
    public boolean exposeProxy() {
        return exposeProxy;
    }
    //设置 是否允许代理对象作为 ThreadLocal 通过 AopContext 访问
    public void setExposeProxy(boolean exposeProxy) {
        this.exposeProxy = exposeProxy;
    }
}
